package fileformat

import (
	"io/ioutil"
	"log"
	"src/fsm"
	"strings"
	"unicode"
)

type FileFormat struct {
	filename      string
	headerfilefsm *fsm.Machine
	filefsm       *fsm.Machine
	rdata         []rune
	ri            int
	rtotal        int
	wdata         []rune
}

func NewFileFormat(file string) *FileFormat {
	ff := &FileFormat{
		filename: file,
	}

	ff.initHeaderFileFsm()
	ff.initFileFsm()

	return ff
}

func (ff *FileFormat) reset() {
	ff.ri = 0
	ff.rtotal = 0
	ff.rdata = []rune{}
	ff.wdata = []rune{}
}

func (ff *FileFormat) getRune() rune {
	d := rune(' ')
	if ff.ri < ff.rtotal {
		d = ff.rdata[ff.ri]
		ff.ri++
	}

	return d
}

func (ff *FileFormat) putRune(v rune) {
	ff.wdata = append(ff.wdata, v)
}

func (ff *FileFormat) readValid() bool {
	if ff.ri < ff.rtotal {
		return true
	}
	
	return false
}

func (ff *FileFormat) trimSpace() {
	for ff.ri < ff.rtotal {
		if !unicode.IsSpace(ff.rdata[ff.ri]) {
			break	
		}
		ff.ri++
	}
}

func (ff *FileFormat) Format() error {
	ff.reset()
	log.Println("goto fileformat ", ff.filename)
	if strings.HasSuffix(ff.filename, ".h") {
		ff.FormatHeaderFile()
	}
	if strings.HasSuffix(ff.filename, ".c") {
		ff.FormatFile()
	}

	return nil
}

func (ff *FileFormat) FormatHeaderFile() {
	ff.headerfilefsm.Execute(ff)
}

func (ff *FileFormat) FormatFile() {
	ff.filefsm.Execute(ff)
}

func begin(v interface{}) (string, interface{}) {
	ff := v.(*FileFormat)
	//读取所有数据
	data, err := ioutil.ReadFile(ff.filename)
	if err != nil {
		log.Fatal("read failed name=", ff.filename, " err=", err)
	}
	ff.rdata = []rune(string(data))
	ff.rtotal = len(ff.rdata)


	return "common", v
}

func common(v interface{}) (string, interface{}) {
	ff := v.(*FileFormat)

	for {
		//先去掉行首的空格
		ff.trimSpace()
		if !ff.readValid() {
			break
		}
		lv := ff.getRune()
			
		if lv == rune('#')	 {
			ff.putRune(lv)
			//处理宏行
			return "star_key", v
		}

		//其它默认写入
		ff.putRune(lv)
	}


	return "finish", v
}


func star_key(v interface{}) (string, interface{}) {
	ff := v.(*FileFormat)
	ff = ff
	
	return "common", v
}


func finish(v interface{}) (string, interface{}) {
	ff := v.(*FileFormat)
	if len(ff.wdata) > 0 {
		dstfile := ff.filename + "_back"
		dstdata := []byte(string(ff.wdata))
		log.Print("dstdata len=", len(dstdata))
		ioutil.WriteFile(dstfile, dstdata, 0)
	}

	return "end", v
}

func (ff *FileFormat) initHeaderFileFsm() {
	f := fsm.New()
	f.AddState("begin", begin)
	f.AddState("common", common)
	f.AddState("star_key", star_key)
	f.AddState("finish", finish)
	f.AddState("end", nil)
	f.AddEndState("end")
	f.SetStartState("begin")

	ff.headerfilefsm = f
}

func (ff *FileFormat) initFileFsm() {

	ff.filefsm = fsm.New()
}
